package com.dale.controller;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.map.MapUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.dale.common.dto.BlogDto;
import com.dale.common.lang.Result;
import com.dale.entity.Blog;
import com.dale.entity.MetaBlog;
import com.dale.service.BlogService;
import com.dale.service.MetaBlogService;
import com.dale.service.SimilarBlogService;
import com.dale.shiro.AccountProfile;
import com.dale.util.QiniuUtils;
import com.dale.util.SensitiveFilter;
import com.dale.util.ShiroUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.Assert;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
import java.util.UUID;

/**
 * <p>
 * 前端控制器
 * </p>
 *
 * @author ：dale
 * @since 2020-05-25
 */

@Slf4j
@RestController
public class BlogController {

    @Autowired
    private BlogService blogService;


    @Autowired
    private SimilarBlogService similarBlogService;

    @Autowired
    private MetaBlogService metaBlogService;

    @Value("${server.port}")
    private String port;


    /**
     * 主页展示
     *
     * @param currentPage
     * @return
     */
    @GetMapping("/blogs")
    public Result list(@RequestParam(defaultValue = "1") Integer currentPage) {

        //MybatisPlus分页  参数(起始页面、个数)
        Page page = new Page(currentPage, 10);
        //根据创建时间倒叙（最新在前）
        //提示：这里也可以逻辑删除判断筛选哈
//        IPage pageData = blogService.page(page, new QueryWrapper<Blog>().orderByDesc("created"));
        IPage pageData = blogService.selectAllBlogs(page);
        return Result.succ(pageData);
    }


    /**
     * 自实现
     * 查询当前用户的文章
     *
     * @param
     * @param currentPage
     * @return
     */
    @RequiresAuthentication
    @GetMapping("/blogOfUser")
    public Result blogOfUser(@RequestParam(defaultValue = "1") Integer currentPage) {
//        List<Blog> user_id = blogService.list(new QueryWrapper<Blog>().eq("user_id", String.valueOf(userId)));

        AccountProfile profile = ShiroUtil.getProfile();
        Long userId = profile.getId();

        //MybatisPlus分页  参数(起始页面、个数)
        //MybatisPlus分页  参数(起始页面、个数)
        Page page = new Page(currentPage, 5);
        //根据创建时间倒叙（最新在前）
        //提示：这里也可以逻辑删除判断筛选哈
        IPage pageData = blogService.page(page, new QueryWrapper<Blog>()
                .orderByDesc("created")
                .eq("user_id", userId.longValue())
                .orderByDesc("created"));

        return Result.succ(pageData);

    }

    /**
     * 详情页面
     * 使用来了RestFul风格
     * //都可访问
     *
     * @param id 利用文章id 获取文章主要内容
     * @return
     */
    @GetMapping("/blog/{id}")
    public Result detail(@PathVariable(name = "id") Long id) {
        Blog blog = blogService.getById(id);
        //若id查出为空（就是防止用户直接url中更改）
        Assert.notNull(blog, "该博客已被删除");

        blog.setView(blog.getView() + 1);

        blogService.updateById(blog);

        return Result.succ(blogService.getBlogDtoById(id));
    }

    /**
     * 添加、修改文章  统一体
     * 利用是否有id来区分
     * 有validated校验字段是否完整  详细见Blog实体类
     * <p>
     * post请求哈
     *
     * @param blog
     * @return
     * @RequiresAuthentication：表示需要认证后才能访问：（验证的是JWT）
     */
    @RequiresAuthentication
    @PostMapping("/blog/edit")
    @RequiresRoles(value = {"common", "admin"}, logical = Logical.OR)     //表示是普通用户 或者 admin用户可访问
    public Result edit(@Validated @RequestBody Blog blog) {

        //敏感词检测 并替换
        String content = SensitiveFilter.replaceWords(blog.getContent());
        String title = SensitiveFilter.replaceWords(blog.getTitle());
        String description = SensitiveFilter.replaceWords(blog.getDescription());

        blog.setContent(content);
        blog.setTitle(title);
        blog.setDescription(description);

        //用于区分创建文章还是修改文章  默认创建
        boolean createBlogFlag = true;

        Blog temp = null;
        if (blog.getId() != null) {
            //id存在 修改文章
            temp = blogService.getById(blog.getId());
            createBlogFlag = false;
            // 只能编辑自己的文章
//            System.out.println(ShiroUtil.getProfile().getId());

            //用于判断是否是自己的文章：只能修改自己的文章
            //ShiroUtil自己写的 点开看  返回的是当前 用户的部分信息对象
            //利用断言处理  不是当前用户则  抛出异常IllegalArgumentException   然后被全局捕获哦  然后回显前端
            //longValue将封装的Long返回long

            Assert.isTrue(temp.getUserId().longValue() == ShiroUtil.getProfile().getId().longValue(), "没有权限编辑");

        } else {
            //id不存在  添加文章
            createBlogFlag = true;
            temp = new Blog();
            temp.setUserId(ShiroUtil.getProfile().getId());
            temp.setCreated(LocalDateTime.now());
            temp.setStatus(0);
//            temp.setAvatar(ShiroUtil.getProfile().getAvatar());
//            temp.setAuthor(ShiroUtil.getProfile().getUsername());
        }

        //将temp信息赋值给  前端传来的blog   并忽略掉后面的字段（因为blog中这些字段为null  上面的else已经为temp填充）
        temp.setUpdated(LocalDateTime.now());
        BeanUtil.copyProperties(blog, temp, "id", "userId", "created", "status", "updated");
        blogService.saveOrUpdate(temp);


        //如果刚刚是创建文章
        if (createBlogFlag) {
            //查询到刚刚创建文章的id 这里就比较复杂   就利用作者id和时间来搜素
            Blog one = blogService.getOne(new QueryWrapper<Blog>().eq("id", temp.getId()));
            //得到id
            Long id = one.getId();
            blog = one;
            //需要计算相似度
            //调用SimilarBlogService  根据这篇文章 计算其于其他所有文章相似度
            similarBlogService.getSimilarity(id);

            //设置成默认
            metaBlogService.save(new MetaBlog().setMid(1L).setBid(id));

        }

        return Result.succ(MapUtil.builder().put("id", blog.getId()).map());
    }

    /**
     * 搜索功能   模糊插叙
     *
     * @param searchContent
     * @param currentPage
     * @return
     */
    @GetMapping("/searchBlog")
    public Result searchBlog(@RequestParam String searchContent, @RequestParam(defaultValue = "1") Integer currentPage) {
        //MybatisPlus分页  参数(起始页面、个数)
        Page page = new Page(currentPage, 10);
        //根据创建时间倒叙（最新在前）
        //提示：这里也可以逻辑删除判断筛选哈

        return Result.succ(blogService.searchBlog(page, searchContent));
    }


    @GetMapping("/recommend")
    public Result recommend() {
        //获取到文章的最大id
        long count = blogService.getMaxId();

        Blog blog = null;
        while (blog == null) {
            //随机找到文章
            int i = new Random().nextInt();
            blog = blogService.getById(Math.abs(i) % count);

        }
//        blog = blogService.getById(1);

        return Result.succ(blog);
    }


    /**
     * 不好哈  已经被弃用
     *
     * 最新见meta
     *
     * 分类说明 ： 目前没使用枚举
     * 1：Java 2:学习 3：生活 4：情感  5：感情 6：工作
     *
     * @param classification
     * @return
     */
//    @GetMapping("/classify")
//    public Result classify(@RequestParam String classification, @RequestParam(defaultValue = "1") Integer currentPage) {
//
//        IPage pageData = null;
//
//        if (classification == null || classification == "") {
//            Page page = new Page(currentPage, 5);
//            //根据创建时间倒叙（最新在前）
//            //提示：这里也可以逻辑删除判断筛选哈
//            pageData = blogService.page(page,
//                    new QueryWrapper<Blog>()
//                            .orderByDesc("created"));
//        } else {
//
//            Page page = new Page(currentPage, 5);
//            //根据创建时间倒叙（最新在前）
//            //提示：这里也可以逻辑删除判断筛选哈
//            pageData = blogService.page(page,
//                    new QueryWrapper<Blog>().eq("classification", classification)
//                            .orderByDesc("created"));
//        }
//        return Result.succ(pageData);
//    }


    /**
     * 博客上传图片  本地上传版
     *
     * @return 返回图片的url地址  拼接到markdown中
     */
//    @RequiresAuthentication
//    @RequiresRoles(value = {"common","admin"},logical = Logical.OR)     //表示是普通用户 或者 admin用户可访问  guest用户不行
//    @PostMapping("/uploadImg")
//    public Result uploadImg(@RequestParam("file") MultipartFile file) {
//        //如果文件名为空  用了Spring工具包判断空
//        if (file.isEmpty()) {
//            return Result.fail("上传寂寞");
//        }
//
//        //获取文件名(OriginalFilename)包括扩展名
//        String OriginalFilename = file.getOriginalFilename();
//
//        //为了防止别人的文件覆盖掉了 所以名字加上时间戳
//        String uploadFileName = System.currentTimeMillis() + "." + OriginalFilename.substring(OriginalFilename.indexOf(".") + 1);
//
//        //这样文件名就是 时间戳 + 扩展名
//        log.info("图片上传:" + uploadFileName);
//
//        //上传保存地址设置  \\表示 转义符\
//        //注意末尾也要加上\\
//        //！！！！！！！！！！！！！！保存到静态资源路径
//        String filepath = "C:\\Users\\28773\\IdeaProjects\\GitProjects\\MarkerHub_vueblog\\vueblog-master\\vueblog-java\\src\\main\\resources\\static\\blogImg\\";
////        String filepath = "static\\avatar";
//        //创建文件哈
//        File dest = new File(filepath + uploadFileName);
//
//        //确保filepath存在
//        if (!dest.getParentFile().exists()) {
//            dest.getParentFile().mkdir();
//        }
//
//        //开始拷贝文件
//        try {
//            file.transferTo(dest);
//        } catch (IOException e) {
//            //可能会出现 硬盘不够等等请求
//            e.printStackTrace();
//            return Result.fail("图片上传失败");
//        }
//
//        //成功上传到本地后 将图片的url地址返回给前端 富文本编辑器
//        //这里的url应该是全名
//        return Result.succ(MapUtil.builder()
//                .put("url", "http://localhost:8081" + "/blogImg/" + uploadFileName)
//                .map());
//    }


    /**
     * 博客上传图片   七牛云哦哦哦哦详情见工具类
     * 参考地址： https://blog.csdn.net/weixin_45019350/article/details/110055899
     *
     * @return 返回图片的url地址  拼接到markdown中
     */
    @RequiresAuthentication
    @RequiresRoles(value = {"common", "admin"}, logical = Logical.OR)     //表示是普通用户 或者 admin用户可访问  guest用户不行
    @PostMapping("/uploadImg")
    public Result uploadImg(@RequestParam("file") MultipartFile file) {
        String originalFilename = file.getOriginalFilename();//获取图片原始文件名
        int index = originalFilename.lastIndexOf(".");
        String extention = originalFilename.substring(index);//获得图片后缀名  .jpg
        String fileName = UUID.randomUUID().toString() + extention; //进行拼接
        fileName = fileName.replace("-", ""); //将文件路径中的-替换掉
//        try {
        //使用工具类将文件上传到七牛云服务器
        String filePath = null;
        try {
            filePath = QiniuUtils.upload2Qiniu(file.getBytes(), fileName);
        } catch (IOException e) {
            System.out.println("上传失败");
        }
        return Result.succ(MapUtil.builder()
                .put("url", filePath)
                .map());
    }


    /**
     * 删除博客
     *
     * @param id
     * @return
     */
    @RequiresAuthentication
    @RequiresRoles(value = {"common", "admin"}, logical = Logical.OR)     //表示是普通用户 或者 admin用户可访问
    @DeleteMapping("/delBlogById/{id}")
    public Result delBlogById(@PathVariable Long id) {
        /*
        逻辑：删除时 先做匹配  只能删除自己的文章
         */


        Long userId = ShiroUtil.getProfile().getId();

        Blog blog = blogService.getOne(new QueryWrapper<Blog>().eq("id", id));

        log.info("准备删除" + blog + "id = " + id);

        //如果不是自己的文章
        Assert.isTrue(userId == blog.getUserId(), "不能删除他人文章");

        blogService.removeById(id);

        return Result.succ(null);
    }


    /**
     * 获取文章前三篇相似文章
     */
    @GetMapping("/getSimilarBlogs/{bid}")
    public Result getSimilarBlogs(@PathVariable Long bid) {
        List<Blog> similarBlogs = similarBlogService.getSimilarBlogs(bid);

        return Result.succ(similarBlogs);
    }

    @PostMapping("/videoUpload/{bid}")
    @RequiresAuthentication
    @RequiresRoles(value = {"common", "admin"}, logical = Logical.OR)
    public Result videoUpload(@PathVariable Long bid, @RequestParam("file") MultipartFile file) {

        //如果文件名为空  用了Spring工具包判断空
        if (file.isEmpty()) {
            return Result.fail("上传寂寞");
        }

        String originalFilename = file.getOriginalFilename();//获取图片原始文件名
        int index = originalFilename.lastIndexOf(".");
        String extention = originalFilename.substring(index);//获得图片后缀名  .jpg
        String fileName = UUID.randomUUID().toString() + extention; //进行拼接
        fileName = fileName.replace("-", ""); //将文件路径中的-替换掉
//        try {
        //使用工具类将文件上传到七牛云服务器
        String filePath = null;
        try {
            filePath = QiniuUtils.upload2Qiniu(file.getBytes(), fileName);

            //上传成功保存到数据库
            Blog byId = blogService.getById(bid);
            byId.setVideo(filePath);
            blogService.updateById(byId);


        } catch (IOException e) {
            System.out.println("上传失败");
        }

        return Result.succ(MapUtil.builder()
                .put("url", filePath)
                .map());
    }


    @PostMapping("/videoUpload2")
    @RequiresAuthentication
    @RequiresRoles(value = {"common", "admin"}, logical = Logical.OR)
    public Result videoUpload2(@RequestParam("file") MultipartFile file) {

        //如果文件名为空  用了Spring工具包判断空
        if (file.isEmpty()) {
            return Result.fail("上传寂寞");
        }

        String originalFilename = file.getOriginalFilename();//获取图片原始文件名
        int index = originalFilename.lastIndexOf(".");
        String extention = originalFilename.substring(index);//获得图片后缀名  .jpg
        String fileName = UUID.randomUUID().toString() + extention; //进行拼接
        fileName = fileName.replace("-", ""); //将文件路径中的-替换掉
//        try {
        //使用工具类将文件上传到七牛云服务器
        String filePath = null;
        try {
            filePath = QiniuUtils.upload2Qiniu(file.getBytes(), fileName);

        } catch (IOException e) {
            System.out.println("上传失败");
        }

        //上传成功保存到数据库  返回url
        return Result.succ(MapUtil.builder()
                .put("url", filePath)
                .map());
    }



    @GetMapping("/getMostLikeTodayBlog")
    public Result getMostLikeTodayBlog(){
        return Result.succ(blogService.getMostLikeTodayBlog());
    }

}
